home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1993 / MacHack 1993.toast / MacHack™ 1987-1992 / MacHack™ '90 / Source Code ƒ / MPW C ƒ / NetTimeProtocol ƒ / ntp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-03-23  |  9.2 KB  |  382 lines  |  [TEXT/MPS ]

  1. #ifndef lint
  2. static char *RCSid = "$Header: ntp.c,v 2.6 89/02/19 16:08:28 bww Exp $";
  3. #endif
  4.  
  5. /*
  6.  * ntp - single shot ntp query
  7.  *
  8.  ****************************************************************
  9.  * HISTORY
  10.  * $Log:    ntp.c,v $
  11.  * Revision 2.6  89/02/19  16:08:28  bww
  12.  *     SSP headers.
  13.  *     [89/02/19  16:05:57  bww]
  14.  * 
  15.  * Revision 2.5  88/11/11  16:06:44  bww
  16.  * Upgraded to latest UMD release.
  17.  * 
  18.  * Revision 2.4  88/08/20  16:57:27  bww
  19.  * Added FD_ZERO() call and checks for errors from gettimeofday().
  20.  * 
  21.  * Revision 2.3  88/08/18  21:12:38  bww
  22.  * Fixed handling of signed octets to be machine independent.
  23.  * 
  24.  * Revision 2.2  88/07/17  15:06:37  bww
  25.  * First CMUCS release
  26.  * 
  27.  * Revision 2.1  88/04/25  17:59:59  root
  28.  * Initial CMU revision
  29.  * 
  30.  * Revision 2.1  88/04/25  17:59:59  root
  31.  * *** empty log message ***
  32.  * 
  33.  * Revision 2.0  88/03/31  10:24:58  root
  34.  * *** empty log message ***
  35.  * 
  36.  * Revision 1.3  88/02/28  23:24:27  root
  37.  * Fixed precision field
  38.  * 
  39.  * Revision 1.2  88/02/28  22:59:10  petry
  40.  * *** empty log message ***
  41.  * 
  42.  * Revision 1.1  87/12/16  10:33:10  root
  43.  * Initial revision
  44.  * 
  45.  */
  46.  
  47. /*
  48.  * This program expects a list of host names.  It will send off a
  49.  * network time protocol packet and print out the replies on the
  50.  * terminal.
  51.  * 
  52.  * Example:
  53.  *    % ntp umd1.umd.edu
  54.  *    Leap indicator: 0    Status: 1    Stratum: 1 (WWVB)
  55.  *    Precision = 2**-10 (dec)
  56.  *    Estimated Drift is -6157
  57.  *    Synchronizing Dist is 0000.1999
  58.  *    Reference Timestamp is 2782090479.031998
  59.  *    Originate Timestamp is 2782090483.463761
  60.  *    Receive Timestamp is   2782090483.461990
  61.  *    Transmit Timestamp is  2782090483.799988
  62.  *    Input Timestamp is     2782090483.832143
  63.  *    umd1.umd.edu: delay:0.030384 offset:-0.016963
  64.  */
  65.  
  66. #include    <Types.h>
  67. #include    <Events.h>
  68. #include    <Math.h>
  69. #include     <fcntl.h>
  70. #include     <stdio.h>
  71. #include    <ErrMgr.h>
  72. #include    <CursorCtl.h>
  73. #include    <Errors.h>
  74. #include    <Devices.h>
  75. #include    <MacTCPCommonTypes.h>
  76. #include    <UDPPB.h>
  77. #include    <TCPPB.h>
  78. #include     <GetMyIPAddr.h>
  79. #include    <AddressXlation.h>
  80. #include    <Time.h>
  81. #include     "ntp.h"
  82.  
  83. #define    TRUE    1
  84. #define FALSE    0
  85. #define NIL 0
  86. #define TICKPERSECOND 60
  87.  
  88. extern char *malloc();
  89.  
  90. static StreamPtr myudpstream    = 0;
  91. static short refnum = 0;
  92. static udp_port myudpport = 0;
  93.  
  94. extern int errno;
  95. #ifdef DEBUG
  96. int debug;
  97. #endif
  98.  
  99. void bzero(char * bytes, int len)
  100. {
  101.     register char *p;
  102.  
  103.     for (p = bytes; len > 0; len--,p++) {
  104.         *p = '\0';
  105.     }
  106. }
  107.  
  108. char *inet_ntoa(ip_addr addr)
  109. {
  110.     static char buf[100];
  111.  
  112.     if (AddrToStr(addr,buf) != noErr) {
  113.         return "?use resolver?";
  114.     } else {
  115.         return buf;
  116.     }
  117. }
  118.  
  119. void clean_exit(int code)
  120. {
  121.     UDPiopb udppb;
  122.  
  123.     if (myudpstream != 0) {
  124.         bzero((char *)&udppb,sizeof(udppb));
  125.         udppb.ioCompletion    = NIL;
  126.         udppb.ioCRefNum        = refnum;
  127.         udppb.csCode         = UDPRelease;
  128.         udppb.udpStream     = myudpstream;
  129.         udppb.csParam.create.userDataPtr    = NIL;
  130.         
  131.     
  132.         if (PBControl((ParmBlkPtr)&udppb,false) != noErr) {
  133.             fprintf(stderr,"Trouble releasing udp stream in clean_exit(%d)\n",code);
  134.         }
  135.     }
  136.     (void)CloseResolver(); /* ignore errors */
  137.     if (code != 0) {
  138.         fprintf(stderr,"exit(%d)\n",code);
  139.     }
  140.     exit(code);
  141. }
  142.  
  143.  
  144. void     FailOSErr(msg, err)
  145.     char    *msg;
  146.     OSErr    err;
  147. {
  148.     if (err != noErr) {
  149.         fprintf(stderr,"%s errcode=%d\n",msg,err);
  150.         clean_exit (-1);
  151.     }
  152. }
  153.  
  154. void     ReportOSErr(msg, err)
  155.     char    *msg;
  156.     OSErr    err;
  157. {
  158.     if (err != noErr) {
  159.         fprintf(stderr,"%s errcode=%d\n",msg,err);
  160.     }
  161. }
  162.  
  163. void
  164. waitforonesecond()
  165. {
  166.     register unsigned long ticks;
  167.     for (ticks = TickCount(); TickCount() < (ticks + TICKPERSECOND);) {
  168.         EventRecord theEvent;
  169.     
  170.         (void)EventAvail(0,&theEvent);
  171.         /* packet();  checks for incoming packets */
  172.     }
  173. }
  174.  
  175.  
  176. main(argc, argv)
  177.     int argc;
  178.     char **argv;
  179. {
  180.     struct hostInfo hp;
  181.     ip_addr clock_host, whofrom;
  182.     struct l_fixedpt in_timestamp;
  183.     static struct ntpdata ntp_data;
  184.     struct ntpdata *pkt = &ntp_data;
  185.     struct timeval tp;
  186.     int host, retry;
  187.     double ul_fixed_to_double();
  188.     double ref, t1, t2, t3, t4, offset, delay;
  189.     char ref_clock[5];
  190.     UDPiopb udppb;
  191.     wdsEntry wds[2];
  192.     char * p;
  193.     int len;
  194.     OSErr    err;
  195.  
  196.  
  197.     InitCursorCtl(nil);
  198.     FailOSErr("OpenResolver", OpenResolver(NIL));
  199.     FailOSErr("Can't open driver",opendriver(".IPP",&refnum));
  200.  
  201.     ref_clock[4] = NULL;
  202.  
  203.     /* grab a udp port, to use for sending packets.  NoDelay, Async */
  204.  
  205.     p = malloc(4096);
  206.     if (p == NULL) {
  207.         fprintf(stderr,"malloc fails\n");
  208.         clean_exit(-1);
  209.     }
  210.     bzero((char *)&udppb,sizeof(udppb));
  211.     udppb.ioCompletion    = NIL;
  212.     udppb.ioCRefNum        = refnum;
  213.     udppb.csCode         = UDPCreate;
  214.     udppb.csParam.create.rcvBuff         = p;
  215.     udppb.csParam.create.rcvBuffLen        = 4096;
  216.     udppb.csParam.create.notifyProc        = NIL;
  217.     udppb.csParam.create.localPort        = 0;
  218.     udppb.csParam.create.userDataPtr    = 0;
  219.  
  220.     FailOSErr("UDPCreate Fails",PBControl((ParmBlkPtr)&udppb,false));
  221.  
  222.     myudpstream = udppb.udpStream;
  223.     myudpport = udppb.csParam.create.localPort;
  224.  
  225.     retry = RETRY_COUNT;
  226.  
  227.  
  228.     for (host = 1; host < argc; ++host) {
  229.         if (argv[host] == NULL)
  230.             continue;
  231.         if (StrToAddr(argv[host],&hp,NIL,NIL) != noErr) {
  232.             fprintf(stderr, "\nNo such host: %s (use IP address for now)\n",
  233.                 argv[host]);
  234.             continue;
  235.         }
  236.  
  237.         bzero((char *)pkt, sizeof(ntp_data));
  238.  
  239.         pkt->status = NTPVERSION_1;
  240.         pkt->stratum = UNSPECIFIED;
  241.         pkt->poll = 0;
  242.         pkt->org.int_part = pkt->org.fraction = 0;
  243.         pkt->rec.int_part = pkt->rec.fraction = 0;
  244.  
  245.         /*
  246.          * Needed to fill in the transmit time stamp field 
  247.          */
  248.         if (gettimeofday(&tp, (struct timezone *) 0) == -1) {
  249.             perror("ntp gettimeofday1");
  250.             clean_exit(1);
  251.         }
  252.         tstamp(&pkt->xmt, &tp);
  253.  
  254.         udppb.ioCompletion    = NIL;
  255.         udppb.ioCRefNum        = refnum;
  256.         udppb.csCode         = UDPWrite;
  257.         udppb.udpStream     = myudpstream;
  258.         udppb.csParam.send.remoteHost      = hp.addr[0];
  259.         udppb.csParam.send.remotePort    = NTP_PORT;
  260.         udppb.csParam.send.userDataPtr    = NIL;
  261.     
  262.         /* build write-data structure */
  263.         wds[0].length    = sizeof(ntp_data);
  264.         wds[0].ptr        = (char *) &ntp_data;
  265.         wds[1].length    = 0;
  266.         
  267.         udppb.csParam.send.wdsPtr    = (Ptr)&wds;
  268.     
  269.         err = PBControl((ParmBlkPtr)&udppb,false);
  270.         if (err == ipDestDeadErr) { /* are there other codes here we should special case? */
  271.             fprintf(stderr,"Host %s not responding, errcode=%d\n",inet_ntoa(hp.addr[0]),err);
  272.             continue;
  273.         } else if (err != noErr) {
  274.             fprintf(stderr,"UDPsend fails errcode=%d\n",err);
  275.             continue;
  276.         }
  277.     
  278.         /*
  279.          * Wait for the reply. 
  280.          */
  281.         bzero((char *)&udppb,sizeof(udppb));
  282.         udppb.ioCompletion    = NIL;
  283.         udppb.ioCRefNum        = refnum;
  284.         udppb.csCode         = UDPRead;
  285.         udppb.udpStream     = myudpstream;
  286.         udppb.csParam.receive.timeOut              = TIME_OUT; /* minimum time */
  287.         udppb.csParam.receive.secondTimeStamp    = 0;
  288.         udppb.csParam.receive.userDataPtr        = NIL;
  289.         err = PBControl((ParmBlkPtr)&udppb,false);
  290.         
  291.         if (err == commandTimeout) {
  292.             fprintf(stderr,"\n\t* Timeout *\n");
  293.             if (--retry)
  294.                 --host;
  295.             else {
  296.                 fprintf(stderr,"\nHost %s is not responding\n",
  297.                     argv[host]);
  298.                 retry = RETRY_COUNT;
  299.             }
  300.             continue;
  301.         } else if (err != noErr) {
  302.             fprintf(stderr,"packet:UDPRead fails (%d)\n", err);
  303.             continue;
  304.         }
  305.         whofrom = udppb.csParam.receive.remoteHost;
  306.     
  307.         /* copy bytes into pkt */
  308.         len = udppb.csParam.receive.rcvBuffLen;
  309.         
  310.         memcpy (&ntp_data, udppb.csParam.receive.rcvBuff, 
  311.                 (sizeof(ntp_data) > len) ? (len) : (sizeof(ntp_data)));
  312.         
  313.         /* release buffer space */
  314.         udppb.csCode         = UDPBfrReturn;
  315.         if (PBControl((ParmBlkPtr)&udppb,false) != noErr) {
  316.             fprintf(stderr,"packet:UDPBfrReturn fails\n");
  317.         }
  318.         if (sizeof(ntp_data) != len) {
  319.             fprintf(stderr,"packet was %d bytes, expected %d\n",len,sizeof(ntp_data));
  320.         }
  321.     
  322.         if (gettimeofday(&tp, (struct timezone *) 0) == -1) {
  323.             perror("ntp gettimeofday2");
  324.             clean_exit(1);
  325.         }
  326.         tstamp(&in_timestamp, &tp);
  327.  
  328.         printf("Packet from: [%s]\n", inet_ntoa(whofrom));
  329.         printf("Leap indicator: %d\tStatus: %d\tStratum: %d",
  330.             (int)(pkt->status >> 6), (int)(pkt->status & 0x03f),
  331.             pkt->stratum);
  332.         switch (pkt->stratum) {
  333.         case 0:
  334.         case 1:
  335.             (void) strncpy(ref_clock, (char *) &pkt->refid, 4);
  336.             ref_clock[4] = '\0';
  337.             printf(" (%s)\n", ref_clock);
  338.             break;
  339.         default:
  340.             clock_host = (u_long) pkt->refid;
  341.             printf(" [%s]\n", inet_ntoa(clock_host));
  342.             break;
  343.         }
  344.         printf("Poll = %d  Precision = 2**%d (dec)\n",
  345.             pkt->poll, char_to_int(pkt->precision));
  346.         printf("Estimated Drift is %ld\n",
  347.             (long) ntohl((u_long) pkt->drift));
  348.         printf("Synchronizing Dist is %04X.%04X\n",
  349.             ntohs((u_short) pkt->distance.sint_part),
  350.             ntohs((u_short) pkt->distance.sfraction));
  351.  
  352.         ref = ul_fixed_to_double(&pkt->reftime);
  353.         t1 = ul_fixed_to_double(&pkt->org);
  354.         t2 = ul_fixed_to_double(&pkt->rec);
  355.         t3 = ul_fixed_to_double(&pkt->xmt);
  356.         t4 = ul_fixed_to_double(&in_timestamp);
  357.  
  358.         printf("Reference Timestamp is %08lx.%08lx  %f\n",
  359.             ntohl(pkt->reftime.int_part),
  360.             ntohl(pkt->reftime.fraction), ref);
  361.         printf("Originate Timestamp is %08lx.%08lx  %f\n",
  362.             ntohl(pkt->org.int_part),
  363.             ntohl(pkt->org.fraction), t1);
  364.         printf("Receive Timestamp is   %08lx.%08lx  %f\n",
  365.             ntohl(pkt->rec.int_part),
  366.             ntohl(pkt->rec.fraction), t2);
  367.         printf("Transmit Timestamp is  %08lx.%08lx  %f\n",
  368.             ntohl(pkt->xmt.int_part),
  369.             ntohl(pkt->xmt.fraction), t3);
  370.         printf("Input Timestamp is     %08lx.%08lx  %f\n",
  371.             ntohl(in_timestamp.int_part),
  372.             ntohl(in_timestamp.fraction), t4);
  373.  
  374.         delay = (t4 - t1) - (t3 - t2);
  375.         offset = (t2 - t1) + (t3 - t4);
  376.         offset = offset / 2.0;
  377.         printf("%s: delay:%f offset:%f\n\n", argv[host], delay, offset);
  378.         (void) fflush(stdout);
  379.     }            /* end of for each host */
  380.     clean_exit(0);
  381. }                /* end of main */
  382.